import type { Mapless } from '..';
import type { IdHubType } from '../core/IdHub';
import IdHub from '../core/IdHub';
import { Manager } from '../core/manager';
import type { ManagerOptions } from '../index.d';

type TextIdHubType = IdHubType & {
  sourceId: string;
  layerId: string;
};

export default class TextManager extends Manager<TextIdHubType> {
  constructor(mapless: Mapless, options?: ManagerOptions) {
    super(mapless, options, 'text');
    this.onInitialized();
  }

  override createIdHub(_idHub?: IdHubType): void {
    const newHub = new IdHub({
      layers: {
        layerId: 'dzmap-text-layer',
      },
      sources: {
        sourceId: 'dzmap-text-source',
      },
    }) as TextIdHubType;
    super.createIdHub(newHub);
  }

  override initLayers() {
    if (!this.mapless) return;
    const sid = this.idHub?.sourceId;
    this.mapless.addEmptySource(sid);
    this.mapless.addLayer({
      id: this.idHub?.layerId,
      type: 'symbol',
      source: sid,
      layout: {
        'text-field': ['get', 'text'],
        'text-font': ['Open Sans Regular'],
        'text-size': ['get', 'size'],
        'text-offset': [0, 0.5],
        'text-anchor': 'top',
      },
      paint: {
        'text-color': ['get', 'color'],
      },
    });
  }

  addText(
    texts: Array<{
      id: string;
      text: string;
      coordinates: [number, number];
      color?: string;
      size?: number;
    }>,
  ) {
    const features = texts.map((text) => ({
      type: 'Feature' as const,
      geometry: {
        type: 'Point' as const,
        coordinates: text.coordinates,
      },
      properties: {
        id: text.id,
        text: text.text,
        color: text.color || '#000000',
        size: text.size || 12,
      },
    }));
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features,
    });
  }

  removeText(id: string) {
    const source = this.mapless?.getSource(
      this.idHub?.sourceId,
    ) as mapboxgl.GeoJSONSource;
    if (source) {
      const data = source.serialize() as {
        data: {
          features: Array<{
            properties?: { id?: string };
          }>;
        };
      };
      if (data?.data?.features) {
        const features = data.data.features.filter(
          (feature) => feature.properties?.id !== id,
        ) as GeoJSON.Feature[];
        source.setData({
          type: 'FeatureCollection',
          features,
        });
      }
    }
  }
}

export const attachText = (mapless: Mapless | undefined, name?: string) =>
  mapless?.use(TextManager, name);
export const getText = (mapless: Mapless | undefined, name?: string) =>
  mapless?.get(TextManager, name);
export const detachText = (mapless: Mapless | undefined, name?: string) =>
  mapless?.unuse(TextManager, name);
